package com.scexample.builder;

import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import com.scexample.common.ErrorCode;
import com.scexample.exception.BusinessException;
import com.scexample.service.MerchantService;
import com.scexample.template.PayMerchantTemplate;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

import java.util.Collection;
import java.util.Objects;

/**
 * @program: scexample
 * @description: 实际业务进件模板类
 * @author: 少男
 * @create: 2021-01-19 11:09
 **/
@Slf4j
public class TemplateBuilder {

    private MerchantService merchantService;

    private PayMerchantTemplate payMerchantTemplate;

    private Byte payCode;

    private ApplicationContext applicationContext;

    private final ThreadLocal<PayMerchantTemplate> templateContainer = new ThreadLocal<>();

    public TemplateBuilder(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public TemplateBuilder build() {
        if (Objects.nonNull(payCode)) {
            if (Objects.isNull(merchantService)) {
                MerchantService temp;
                if (Objects.nonNull(temp = findRefrence(MerchantService.class))) {
                    merchantService = temp;
                } else {
                    throw new BusinessException(ErrorCode.S500.statusCode(), "对接支付第三方进件引用生成失败...");
                }
            }

            PayMerchantTemplate context;
            if (Objects.nonNull(context = templateContainer.get())) {
                payMerchantTemplate = context;
            } else {
                synchronized (TemplateBuilder.class) {
                    context = new PayMerchantTemplate(merchantService, applicationContext, payCode, this);
                    payMerchantTemplate = context;
                    templateContainer.set(context);
                }
            }
            return this;
        }
        throw new BusinessException(ErrorCode.S400.statusCode(), "进件业务对应支付类型为空，执行异常...");
    }

    public TemplateBuilder build(Byte payCode) {
        return build(payCode, MerchantService.class);
    }

    public TemplateBuilder build(Byte payCode, Class<MerchantService> classIn) {
        this.payCode = payCode;
        this.merchantService = findRefrence(classIn);
        return build();
    }

    public TemplateBuilder build(Byte payCode, MerchantService merchantService) {
        return payCode(payCode, merchantService).build();
    }

    private TemplateBuilder payCode(Byte payCode, MerchantService merchantService) {
        this.payCode = payCode;
        this.merchantService = merchantService;
        return this;
    }

    PayMerchantTemplate getPayMerchantTemplate() {
        return this.payMerchantTemplate;
    }

    /**
     * 通过beanfactory来获取封装dubbo引用对象集合的对象信息，从中获取到实际dubbo引用的spring bean
     * @param classType
     * @param <T>
     * @return
     */
    @SneakyThrows
    private <T> T findRefrence(Class<T> classType) {
        ReferenceAnnotationBeanPostProcessor bean = applicationContext.getBean(ReferenceAnnotationBeanPostProcessor.class);
        Collection<ReferenceBean<?>> collection = bean.getReferenceBeans();
        for (ReferenceBean<?> referenceBean : collection) {
            if (referenceBean.getObjectType() == classType) {
                return (T) referenceBean.getObject();
            }
        }
        return null;
    }

    public void close() {
        templateContainer.remove();
    }
}
